本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。
前一篇成功串接Apollo Server 跟Pirsma Client,接著就能利用 Prisma client 的 CRUD 方法翻新 server 的 resolvers。
不過只介紹仿Trello專案要用的 resolvers 的話用到的方法其實不多,還是用官方的範例完整點的簡介 Prisma Client 的 CRUD 方法。
先介紹不包含關聯查詢的CRUD方法。
const result = await prisma.user.findOne({
where: {
id: 42,
},
})
const result = await prisma.user.findOne({
where: {
email: 'alice@prisma.io',
},
})
使用 where 指定查詢的欄位,該欄位必須是ID或獨特值。
對應schema 中帶有 @ID 或 @unique 標籤的欄位:
model User {
id Int @id @default(autoincrement())
//...
email String @unique
//...
}
const user = await prisma.user.findMany({
where: { name: 'Alice' },
})
簡易版,尋找指定欄位與目標值相等的所有資料,可以搭配sorting跟filtering實現更複雜的查詢,這些部分晚點介紹。
where參數不是必需的,當沒有參數的時候就是回傳整個table:
const users = await prisma.user.findMany()
其他幾個比較重要的參數:
可以搭配來建立分頁功能。
const results = await prisma.post.findMany({
skip: 40,
take: 10,
})
const user = await prisma.user.findFirst({
where: { name: 'Alice' },
})
尋找指定欄位與目標值相等的首筆資料。
const c = await prisma.post.findFirst({
where: { name: 'Alice' },
take: -1,
});
需要特別介紹下 findFirst的take,跟findMany不同,並不影響回傳資料的數量,而只看正負值。
take為正值則順著序列取第一筆資料,負值就逆著序列取資料。
const user = await prisma.user.create({
data: { email: 'alice@prisma.io' },
})
用data指定要新增的資料,並回傳該筆資料。
const user = await prisma.user.update({
where: { id: 1 },
data: { email: 'alice@prisma.io' },
})
先以where指定查詢的單筆資料後更新為data中的資料,
只有data中包含的欄位會被更新。
這裡的where跟findOne()一樣必須指定id或unique欄位。
const updatedUserCount = await prisma.user.updateMany({
where: { name: 'Alice' },
data: { name: 'ALICE' },
})
where不用指定獨特欄位,可以一次更新多筆資料。
回傳值是更新了多少筆資料的count。
const user = await prisma.user.upsert({
where: { id: 1 },
update: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io' },
})
where必須指定獨特值欄位,
若資料存在則用update的資料進行更新,
否則用create的資料新增。
const user = await prisma.user.delete({
where: { id: 1 },
})
刪除查詢到的單筆資料,並回傳。
const deletedUserCount = await prisma.user.deleteMany({
where: { name: 'Alice' },
})
刪除查詢到的所有資料。
回傳值是刪除了多少筆資料的count。
const result = await prisma.user.count({
where: { name: 'Alice' }
});
計算查詢到的資料筆數。
const result = await prisma.user.findOne({
where: { id: 1 },
include: { posts: true },
})
query時如果欄位是跟其他model的關聯,則用include指定是否加入查詢。
如果是關聯的關聯,就繼續加在裡面:
const result = await prisma.user.findOne({
where: { id: 1 },
include: {
posts: {
author:{
posts: true
};
},
},
},
})
以上的情況是查詢user情報,其中包含posts的情報,不過如是只需要該user的posts,不需要其他的情報的話呢?
Prisma的fluent API提供只回傳指定關聯欄位資料的方法,像是底下的posts() :
const postsByUser: Post[] = await prisma.user
.findOne({ where: { email: 'alice@prisma.io' } })
.posts()
注意雖然查詢是從user開始的,不過最終是回傳post陣列。
這種查詢方式可以一直串下去,回傳就看最後串的是哪個欄位:
const posts: Post[] = await prisma.profile
.findOne({ where: { id: 1 } })
.user()
.posts()
}
如果兩個model之間有關聯,則可以利用關聯欄位,同時新增兩個model的資料:
這部分搭配Schema一起解釋比較好:
model User {
id Int @id @default(autoincrement())
email String @unique
profile Profile
}
model Profile {
id Int @id @default(autoincrement())
bio String
user User? @relation(fields: [userId], references: [id])
userId Int?
}
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
profile: {
create: { bio: 'Hello World' },
},
},
})
以上是在新增user資料時,同時新增一筆profile資料,並且Prisma會自動新增兩者間的關聯資料。
像是Profile與User的關聯是以userId作外鍵,那Prisma就會自動建立該筆Profile 的userId資訊,確保兩筆新增資料間的關聯。
這個操作反過來從profile入手也是可以:
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
create: { email: 'alice@prisma.io' },
},
},
})
如果新增的資料,其關聯的資料已經存在,則用connect()查詢後建立關聯:
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
connect: { id: 42 },
},
},
})
connect會先查詢資料庫中是否有這個id值的user,查不到的話新增會失敗。
const user = await prisma.profile.create({
data: {
bio: 'The coolest Alice on the planet',
user: {
connectOrCreate: {
where: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io'}
},
},
})
connectOrCreate 的話則是先查詢對象是否存在,存在則建立關聯,否則新建user資料後建立關聯。
不過撰文時 connectOrCreate 還是測試版,要在schema.prisma中加入允許測試版功能的指令才能用:
generator client {
provider = "prisma-client-js"
experimentalFeatures = ["connectOrCreate"] //允許指定的測試功能
}
以上巢狀的關聯功能在update,delete時也能用,搭配起來五花八門,詳細可以看看官方文件。
查詢多筆資料時用orderBy指定目標欄位,以及排序方向
const users = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
})
搜尋全部usr並依照email遞增排序。
或是遞減排序:
users = await prisma.user.findMany({
orderBy: {
email: 'desc',
},
})
也可以同時排序多個欄位,關聯的資料內也可排序:
const usersWithPosts = await prisma.user.findMany({
orderBy: [
{
role: 'desc',
},
{
email: 'desc',
},
],
include: {
posts: {
orderBy: {
title: "desc",
},
select: {
title: true,
},
},
},
});
主要會用到的功能先列到這邊,稍加組合就能做到五花八門的查詢,可以多試試。